ES5 & ES6 实现对象深度克隆

前端在处理数据时,经常会需要对象的克隆,当使用 = 号赋值一个对象时,这是常见的引用赋值.接收方改变任意属性会直接改变赋值方的值.为了不影响源对象,就有了浅克隆和深克隆!

下面的对象直接用 = 号赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let objA = {name: 'YTC', age: '18'}
let objB = objA

console.log(objB.age) //18
objB.age = '3'
console.log(objB.age) //3
console.log(objA.age) //3

/**
* 1. 可以看到objB改变了age属性,直接影响到了objA
* 2. 因为js中的复杂类型(引用类型)使用 = 号赋值时,objA将栈中的内存地址 复制 给objB.
* 3. 所以objA和objB在栈中存储的地址是一样的,也就都指着同一个堆.
* 4. 任意一方修改了任何属性都会影响到对方!!!
*/

image

使用浅克隆解决问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'ES5'

function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) { //非继承属性!
dst[prop] = src[prop];
}
}
return dst;
}

let objA = {name: 'ytc', info: {age: '18', sex: '男'}}
let objB = shallowCopy(objA)

console.log(objB) // {name: 'ytc', info: {age: '18', sex: '男'}}
objB.name = 'Terence'
console.log(objB) // {name: 'Terence', info: {age: '18', sex: '男'}}
console.log(objA) // {name: 'ytc', info: {age: '18', sex: '男'}}
//objB改变了name属性,objA没有受到影响
// ------------------------------------------------------------------
objB.info.age = '3'
console.log(objB) // {name: 'Terence', info: {age: '3', sex: '男'}}
console.log(objA) // {name: 'ytc', info: {age: '3', sex: '男'}}
//objB改变了info属性的age属性,objA的age也改变了
// ------------------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'ES6'

let objA = {name: 'ytc', info: {age: '18', sex: '男'}}
let objB = Object.assign({}, objA)

console.log(objB) // {name: 'ytc', info: {age: '18', sex: '男'}}
objB.name = 'TerenceYu'
console.log(objB) // {name: 'TerenceYu', info: {age: '18', sex: '男'}}
console.log(objA) // {name: 'ytc', info: {age: '18', sex: '男'}}
//objB改变了name属性,objA没有受到影响
// ------------------------------------------------------------------
objB.info.age = '666'
console.log(objB) // {name: 'TerenceYu', info: {age: '666', sex: '男'}}
console.log(objA) // {name: 'ytc', info: {age: '666', sex: '男'}}
//objB改变了info属性的age属性,objA的age也改变了

image

1
2
3
4
/**
* 1. 以上是对象的浅克隆,也可以说是对象的 一层 深克隆!
* 2. Object.assign会跳过那些值为 null 或 undefined 的源对象!
*/

使用深克隆解决问题

1
2
3
4
5
6
7
8
9
10
'喵喵喵???'

'看了B乎上尤大大回复的: "任意对象的深度克隆,edge case 非常多,' +
'比如原生 DOM/BOM 对象怎么处理,RegExp 怎么处理,函数怎么处理,' +
'原型链怎么处理... 并不是一个简单的问题。"'

'---> 好吧,深克隆的适用范围不广,下面提供一种黑科技...'

let objA = {name: 'ytc', info: {age: '18', sex: '男'}}
let objB = JSON.parse(JSON.stringify(objA))

image

总结

1. 使用Object.assign()就可以满足普通业务场景.
2. 需要深克隆,使用转JSON的方法也很方便.

-------------本文结束 感谢您的阅读-------------